Skip to content

Add a Timings tab with WuwaLAB ability frame data - #3

Merged
WolfExplode merged 22 commits into
mainfrom
ability-timings
Oct 1, 2026
Merged

WolfExplode merged 22 commits into
mainfrom
ability-timings

Conversation

@WolfExplode

Copy link
Copy Markdown
Owner

Requested by Wolf · project thread

Before: the Characters page showed which button casts each move, but nothing about how long a move takes or when you can cancel or swap out of it.

After: a Timings tab sits next to Moves and is laid out like WuwaLAB's Abilities tab. Abilities are grouped by section (Intro / Outro, Basic Attack, Heavy Attack, ...). Each row shows hits, total frames (bold), the cancel frame, the no-swap window, time stop, motion stop and cooldown. Each row also shows WuwaLAB's chips, like TIME STOP 503F, and the frame each hit lands on. You can filter by name and switch between frames and seconds (60 fps). The page credits WuwaLAB and links to that character's page.

The frame data covers 39 characters and 954 abilities. It was read from WuwaLAB's rendered ability pages on Wolf's PC and keeps only timing columns, per the app's rule of buttons and timing only, no damage.

How: static/data/ww_timings.json is keyed by the character ids in ww_characters.json, so the page looks timings up for the selected character. tools/ww_import_timings.py rebuilds that file from a scrape: it matches WuwaLAB names to ours (XuanLing maps to Yangyang: Xuanling) and drops every non-timing column. tests/test_ww_timings.py covers the name matching, the column filtering, and checks that the shipped file has no damage fields.

Checked in Chromium at desktop and phone widths, including the filter, the seconds toggle, and the table scrolling sideways on narrow screens. All 135 Python tests (under xvfb) and the JS tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4


Generated by Claude Code

The Characters page gets a Timings tab next to Moves, laid out like
WuwaLAB's Abilities tab: abilities grouped by section, with hits, total
frames, cancel frame, no-swap window, time stop, motion stop, cooldown,
WuwaLAB's chips (TIME STOP / MOTION STOP) and each hit's frame. It has a
name filter and a frames/seconds toggle (60 fps), and credits WuwaLAB.

- static/data/ww_timings.json: 39 characters, 954 abilities, keyed by
  the ids in ww_characters.json. Timing columns only, no damage.
- tools/ww_import_timings.py rebuilds it from a WuwaLAB scrape.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
@WolfExplode WolfExplode self-assigned this Oct 1, 2026
claude and others added 21 commits October 1, 2026 12:57
PyInstaller now lives in requirements.txt, so the build job's
"-r requirements-build.txt" failed with "No such file". Install from
requirements.txt only, and update the README's build step to match.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
The layout was capped at 1400px and centered, so on a wide window the
roster sat far right of the search box with an empty gap on its left.
It now fills the width, lined up with the top bar.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
- Main app: a handle on the rail's right edge resizes it (200-480px).
  Double-click resets to 256px. Hidden when the rail is collapsed or on
  phones. While dragging, iframes ignore the pointer so the Characters
  page can't swallow the drag.
- Characters page: a bar between the character list and the detail
  panel resizes the list (200-900px); the grid adds columns as it
  widens. Double-click resets. Hidden on narrow windows.

Both widths are remembered per browser.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Static files had no Cache-Control header, so after an update the browser
could keep a cached characters.html (no resize bar) while loading the new
characters.js. The script then failed on the missing bar, leaving the
character list empty and the detail text squeezed into one column.
Ctrl+F5 on the main page doesn't reload the Characters iframe.

- Static files are now sent with "Cache-Control: no-cache", so the
  browser re-checks each file on load (a 304 when unchanged).
- The Characters page skips the resize bar if the page doesn't have one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Characters can now have a "skill_chain" in ww_characters.json: names for
E pressed again and again in a row (only waits between). Augusta's is
Strike, Leap, Plunge. A single E stays "Skill"; when a second E follows,
the labeler calls label.onRevise so the timeline renames the first tile
to "Strike". Any other move, a held E, or running past the end of the
chain goes back to plain "Skill". The Moves tab lists the chain.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Skill, Liberation, Intro and named Heavies now show the move's own name
from ww_characters.json ("Warrior's Blade", "Sunward Conquest", "Stride
of Goldenflare", "Steelclash", "Strike") instead of "Augusta Skill":
the tile's icon and key already say what kind of move it is. A held E is
"<skill> (held)". Moves without their own name keep the character
("Augusta Basic 2", "Augusta Echo"), as does any character the data
doesn't know.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
- Move names no longer widen their tile: the label has no say in the
  tile's width (contain: inline-size) and is cut with "…"; hovering
  shows the full name.
- Echo tiles read "Echo" instead of "<character> Echo".
- Iuno's held LMB is her Heavy, Flux (swaps Moonring and Moonbow).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Each ability row opens WuwaLAB's frame strip: the animation as a bar with a
tick per hit and the part after the cancel frame shaded.

Pages with WuwaLAB's extra Concerto/Energy columns were scraped one column
off, so the priority number showed up as the cooldown (Iuno's intro read
11f). The importer now only keeps a cooldown when the row's move type sits
where it should.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Timings now come from the full WuwaLAB scrape, read by column name: real
cooldowns, a Concerto column, and the motion/time-stop bands on the frame
strip. Damage columns are still left out.

The timeline keeps each character's Concerto as moves land (base-form
values, starting at 0), and swapping out with a full bar fires the Outro
and empties it. Iuno's held LMB reads Absolute Fullness while her bar is
full, Flux otherwise. Hovering a move name shows the Concerto after it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
A wait written with a leading - works like wait: but doesn't hold you
back: pressing a key during it ends the wait and the press counts for the
next step. Waiting it out is fine too. Works after a key (one tile, as
with wait:) or on its own. Optional waits get a dashed edge on the
timeline, keep their - on inline edits, and are highlighted like waits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Dragging a Combo Steps tile, or clicking one, highlights the inputs that
make it in the Edit combo box (scrolled into view) and outlines the tile.
It's the reverse of the existing cursor-to-tile focus and, like it, only
follows tokens that still match the saved combo. Clicking elsewhere or
typing clears it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Swapping with 1/2/3 alone now reads "Swap" on the timeline. A swap written
with its animation lock, wait(2, 0.9s), is the Intro: it takes the Intro's
name and Concerto, empties the outgoing character's bar (their Outro) and
sets where LMB picks the Basic chain back up.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
The Edit steps toggle and the trash icon on each tile are gone. Steps can
always be dragged and double-click edited, and right-clicking a Combo Steps
tile opens a small menu (Delete step for now) in place of the browser's
menu. Ctrl+Z still undoes. The browser menu stays everywhere else.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Keys alone can't always tell a move apart (LMB after a dodge is a Dodge
Counter or Basic 1; a held LMB can be Heavy 1 or 2). Right-clicking a
Combo Steps tile now lists the moves that key can cast for that character
(WuwaLAB's list, best guess first). The pick is saved in the inputs as a
quoted name after the key, lmb "Basic: Origin Calculus 1", and the
timeline name, the Basic chain after it and the Concerto estimate follow
it. The tracker ignores the name when checking presses.

Inputs splitting skips commas inside quotes, names keep their case on
save, inline edits keep a step's name, and names are colored in the
Inputs box.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Each WuwaLAB move now shows the keys that cast it, written like combo
inputs: lmb1-lmb4 for the Basic chain, rmb, lmb for a Dodge Counter,
space, lmb in mid-air, hold(lmb), e, r, f, swap in/out. It's worked out
from the move's type and name; passives and follow-on effects show a dash.
The Moves tab's key-to-move list it replaces is removed (the chain,
notes and follow-ups stay).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
… order

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
… each move's frames

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XnctbwSWKszAPHhVFMYjj4
@WolfExplode
WolfExplode merged commit 81db208 into main Oct 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants